package tomasulo.unit;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

import tomasulo.Driver;

public class CPU {
	
	private int tick = 0;
	private Queue<CPUListener> listenerQueue = null;
	private Instr instr = null;
	boolean issued = true;
	
	public CPU() {
		listenerQueue = new LinkedList<CPUListener>();
	}
	
	public void addListener(CPUListener listener) {
		listenerQueue.add(listener);
	}
	
	
	/**
	 * Drive the CPU to the next tick;
	 */
	public void drive() {		
		++tick;
		System.out.println("Clock " + tick + ":");
		if (issued) {
			instr = Driver.getFLOS().nextInstr();
			System.out.println(instr.op.toString());
		}
		
		// Notify FU to check CDB
		Driver.getFU().checkCDB(tick);
		
		// Notify all listeners to execute checkCDB() 
		Iterator<CPUListener> iter = listenerQueue.iterator();
		while (iter.hasNext()) {
			iter.next().checkCDB(tick);
		}
		
		// Ask listeners if this instruction can be issued
		issued = false;
		iter = listenerQueue.iterator();
		while (iter.hasNext()) {
			if (iter.next().issue(instr)) {
				issued = true;
				instr.setTimeIssue(tick);
				break;
			}
		}
		
		// Update UI
		Driver.update();
		
		// Notify all listeners to execute afterTick() 
		iter = listenerQueue.iterator();
		while (iter.hasNext()) {
			iter.next().afterTick(tick + 1);
		}
	}
	
	public void reset() {
		// TODO: reset CPU;
		tick = 0;
		issued = true;
		Driver.getFU().reset();
		Iterator<CPUListener> iter = listenerQueue.iterator();
		while (iter.hasNext()) {
			iter.next().reset();
		}
	}
	
	public int getTick() {
		return tick;
	}
	
}
